﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.ComponentModel;

using Common;

namespace SimulationTimer
{
    public class Clock : INotifyPropertyChanged, IDisposable
    {
        private Timer _update;
        private TimeSpan _span;
        private DateTime _current;
        private DateTime _simulationStartDate;
        private DateTime _simulationEndDate;
        private DateTime _simulationStarted;
        private DateTime _previous;
        private double _interval;
        private int _updateCount = 0;
        private double _updateInterval = 3600; // Seconds
        private bool _active = false;

        public bool Active
        {
            get
            {
                return _active;
            }
        }

        public string CurrentDateTime
        {
            get
            {
                DateTime res = CurrentTime;

                if (res >= _simulationEndDate)
                {
                    NotifyPropertyChanged("RunTime");
                    return "Simulation Finished";
                }
                else
                    return res.ToString();
            }
        }

        public string RunTime
        {
            get
            {
                TimeSpan total = DateTime.Now - _simulationStarted;

                return (total.Hours.ToString() + ":" + total.Minutes.ToString() + ":" + total.Seconds.ToString() + ":" + total.Milliseconds.ToString()); 
            }

        }

        public DateTime CurrentTime
        {
            get
            {
                DateTime res;

                //.000001902
                // Actual time transpired
                TimeSpan _t = DateTime.Now - _simulationStarted;

                double _transpired = _t.TotalSeconds * _interval;
                
                //_t = new TimeSpan(0, 0, (int)_transpired); /// BAD

                res = (_simulationStartDate.AddSeconds(_transpired));

                if (res > _simulationEndDate)
                {
                    if (_update != null)
                        _update.Stop();
                }

                return res;
            }
        }

        public DateTime SimulationStartDate
        {
            get
            {
                return _simulationStartDate;
            }
            set
            {
                _simulationStartDate = value;
            }
        }

        public DateTime SimulationEndDate
        {
            get
            {
                return _simulationEndDate;
            }
            set
            {
                _simulationEndDate = value;
            }
        }

        public Double Interval
        {
            get
            {
                return _interval;
            }
            set
            {
                _interval = value;
            }
        }


        public Clock()
        {
            _interval = 1;
            _simulationStarted = DateTime.Now;
            _simulationEndDate = _simulationEndDate.AddYears(1000);
        }

        public Clock(DateTime Start, DateTime End, double Interval)
        {
            _simulationStartDate = Start;
            _simulationEndDate = End;
            _interval = Interval;
            _interval = 1;
            _simulationStarted = DateTime.Now;
        }

        #region Cleanup
        public void Dispose()
        {
        }

        ~Clock()
        {

            Dispose();
        }
        #endregion

        public void Start()
        {

            // I'm not sure we can do a straight simulaton.

            // Do this instead:
            // Write a deterministic function that accepts StartDateTime, Simulation Factor, and then returns SimulationDateTime
            // 1 tick == 100 ns

            _simulationStarted = DateTime.Now;

            _update = new Timer(2000);
            _update.AutoReset = true;
            _update.Elapsed += _update_Elapsed;
            _update.Start();

        }

        protected void _update_Elapsed(object sender, ElapsedEventArgs e)
        {
            NotifyPropertyChanged("CurrentDateTime");
        }

        protected long ConvertMillisecondsToTicks(double i)
        {
            return ((long)i) * 1000000;
        }


        public void End()
        {

        }




        #region Events
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string id)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(id));
        }

        protected void InvokeTimeNotifyEvent(string time)
        {
            if (OnTimeNotify == null) return;

            EventArgs args = new TimeNotifyEventArgs(time);

            OnTimeNotify.Raise(null, args);
        }

        public delegate void TimeNotifyHandler(object sender, TimeNotifyEventArgs e);
        public event TimeNotifyHandler OnTimeNotify;

        #endregion
    }



    public class TimeNotifyEventArgs : EventArgs
    {
        public string CurrentTime { get; private set; }

        public TimeNotifyEventArgs(string time)
        {
            CurrentTime = time;
        }
    }
}
